﻿// Dll1.cpp : 定义 DLL 的导出函数。
//

#include "pch.h"
#include "framework.h"
#include "cikutools.h"
#include <fstream>
#include <iostream>
#include <string>
#include <vector>
#include <winsqlite/sqlite3.h>
#include "FileMap.cpp"

#ifdef _WIN64
#pragma comment(lib, "x64/sqlite3.lib")
#else
#pragma comment(lib, "x86/sqlite3.lib")
#endif // _WIN64


size_t ExportToFile(sqlite3 *pdb, wchar_t sql[], wchar_t filepath[])
{
	char* _sql = UnicodeToUtf8(sql);
	std::ofstream outfile;
	sqlite3_stmt *stmt;
	const unsigned char *pTmp;
	std::string buff = "";
	size_t rows = 0;
	size_t nRet = sqlite3_prepare_v2(pdb, _sql, -1, &stmt, 0);

	if (nRet != SQLITE_OK) {
		sqlite3_finalize(stmt);
		return 0;
	}
	int cols = sqlite3_column_count(stmt);
	if (cols = 0) {
		sqlite3_finalize(stmt);
		return 0;
	}
	outfile.open(filepath, std::ios::out | std::ios::trunc | std::ios::binary);
	outfile.write("\xEF\xBB\xBF", 3);	// UTF8-BOM

	while (sqlite3_step(stmt) == SQLITE_ROW)
	{
		std::string rowdata = static_cast<std::string>((LPCSTR)sqlite3_column_text(stmt, 0));
		for (int i = 1; i < cols; i++) {
			pTmp = sqlite3_column_text(stmt, i++);
			rowdata += '\t';
			if (pTmp != NULL) {
				rowdata += static_cast<std::string>((LPCSTR)pTmp);
			}
		}
		buff += rowdata;
		buff += '\n';
		rows++;

		if (rows % 10000 == 0) {
			char const* p = (char const*)buff.c_str();
			outfile.write(p, buff.length());
			buff.clear();
		}
	}
	if (buff.length() > 0) {
		char const* p = (char const*)buff.c_str();
		outfile.write(p, buff.length());
		buff = "";
	}
	outfile.close(); sqlite3_finalize(stmt);
	return rows;
}

size_t ImportToDB(sqlite3 *pdb, wchar_t sql[], wchar_t filepath[], int duoyi)
{
	sqlite3_stmt *stmt;
	int ret = sqlite3_exec(pdb, "begin;", 0, 0, 0);
	if (ret) {
		//std::cout << "ErrorCode:" << ret << std::endl;
		return -1;
	}
	ret = sqlite3_prepare_v2(pdb, UnicodeToUtf8(sql), -1, &stmt, 0);
	if (ret) {
		//std::cout << "ErrorCode:" << ret << std::endl;
		return -1;
	}
	int paras = sqlite3_bind_parameter_count(stmt);
	FileMap infile;
	int Wide = infile.Open(filepath);
	if (Wide < 0) {
		//std::cout << "打开文件失败！\n";
		sqlite3_finalize(stmt);
		return -2;
	}
	//std::cout << "文件编码:" << infile.FileEncoding << std::endl;
	char delimiters = '\t';
	void(*pfunc)(sqlite3_stmt* stmt, std::string& line, char& delimiters, int& paras);
	pfunc = duoyi == 2 ? ImportLine_json 
		: wcsstr(sql, L"'pinyin'") != NULL 
		? (duoyi == 1 ? ImportLine_duoyi_py : ImportLine_py) 
		: (duoyi == 1 ? ImportLine_duoyi : ImportLine);
		
	if (Wide == 2) {
		std::wstring wline = L"";
		int blen = 1024;
		char *buff = new char[blen];
		//delimiters识别
		if (infile.ReadLine(wline) > -1) {
			char* s = UnicodeToUtf8(wline.c_str());
			for (size_t i = 0; i < strlen(s); i++) {
				if (s[i] == '\t' || s[i] == ' ' || s[i] == '=') {
					delimiters = s[i];
					break;
				}
			}
			delete[] s;
			wline.clear();
			infile.pcur = infile.head;
		}
		else return -3;
		while (infile.ReadLine(wline) > -1) {
			const wchar_t* ps = wline.c_str();
			int wLen = (int)wline.size();
			int sLen = WideCharToMultiByte(CP_UTF8, NULL, ps, wLen, NULL, 0, NULL, NULL);
			if (sLen + 1 > blen) {
				delete[] buff;
				blen = 2 * (sLen + 1);
				buff = new char[blen];
			}
			WideCharToMultiByte(CP_UTF8, NULL, ps, wLen, buff, sLen, NULL, NULL);
			buff[sLen] = '\0';
			std::string line = buff;
			(*pfunc)(stmt, line, delimiters, paras);
			wline.clear();
		}
		delete[] buff;
	}
	else {
		std::string line = "";
		//delimiters识别
		if (infile.ReadLine(line) > -1) {
			size_t t = line.find_first_of("\t =");
			if (t != std::string::npos) {
				delimiters = line[t];
			}
			line.clear();
			infile.pcur = infile.head;
		}
		else return -3;
		if (Wide == 1) {
			while (infile.ReadLine(line) > -1) {
				(*pfunc)(stmt, line, delimiters, paras);
				line.clear();
			}
		}
		else {
			int WLen = 1024, MLen = 1024;
			char *Mbuff = new char[MLen];
			wchar_t *Wbuff = new wchar_t[WLen];
			while (infile.ReadLine(line) > -1) {
				const char* ps = line.c_str();
				int len = (int)line.size();
				int sLen = MultiByteToWideChar(CP_ACP, NULL, ps, len, NULL, NULL);
				if (sLen + 1 > WLen) {
					delete[] Wbuff;
					WLen = 2 * (sLen + 1);
					Wbuff = new wchar_t[WLen];
				}
				MultiByteToWideChar(CP_ACP, NULL, ps, len, Wbuff, sLen);
				Wbuff[sLen] = '\0';
				int ulen = WideCharToMultiByte(CP_UTF8, NULL, Wbuff, sLen, NULL, 0, NULL, NULL);
				if (ulen + 1 > MLen) {
					delete[] Mbuff;
					MLen = 2 * (MLen + 1);
					Mbuff = new char[MLen];
				}
				WideCharToMultiByte(CP_UTF8, NULL, Wbuff, sLen, Mbuff, ulen, NULL, NULL);
				Mbuff[ulen] = '\0';
				std::string mline = Mbuff;
				(*pfunc)(stmt, mline, delimiters, paras);
				line.clear();
			}
			delete[] Mbuff;
			delete[] Wbuff;
		}
	}

	sqlite3_finalize(stmt);
	sqlite3_exec(pdb, "commit", 0, 0, 0);
	infile.Close();
	return 0;
}

void ImportLine(sqlite3_stmt* stmt, std::string& line, char& delimiters, int& paras) {
	std::vector<std::string> secs;
	split(line, secs, delimiters);
	int vlen = (int)secs.size();
	for (int i = 0; i < vlen; i++) {
		sqlite3_bind_text(stmt, i + 1, secs[i].c_str(), -1, 0);
	}
	if (vlen < paras) {
		int i = 0;
		while (vlen + i < paras) {
			i++;
			sqlite3_bind_text(stmt, vlen + i, "", -1, 0);
		}
	}
	sqlite3_step(stmt);
	sqlite3_reset(stmt);
}
void ImportLine_py(sqlite3_stmt* stmt, std::string& line, char& delimiters, int& paras) {
	std::vector<std::string> secs;
	split(line, secs, delimiters);
	int vlen = (int)secs.size();
	if (vlen == 3) {
		sqlite3_bind_text(stmt, 1, secs[0].c_str(), -1, 0);
		sqlite3_bind_text(stmt, 2, secs[1].c_str(), -1, 0);
		sqlite3_bind_text(stmt, 3, secs[2].c_str(), -1, 0);
		sqlite3_bind_text(stmt, 4, szm(secs[0]).c_str(), -1, 0);
	}
	else if (vlen == 2) {
		sqlite3_bind_text(stmt, 1, secs[0].c_str(), -1, 0);
		sqlite3_bind_text(stmt, 2, secs[1].c_str(), -1, 0);
		sqlite3_bind_int(stmt, 3, 5000);
		sqlite3_bind_text(stmt, 4, szm(secs[0]).c_str(), -1, 0);
	}
	sqlite3_step(stmt);
	sqlite3_reset(stmt);
}
void ImportLine_duoyi(sqlite3_stmt* stmt, std::string& line, char& delimiters, int& paras) {
	std::vector<std::string> secs;
	split(line, secs, delimiters);
	int vlen = (int)secs.size();
	for (int i = 1; i < vlen; i++) {
		sqlite3_bind_text(stmt, 1, secs[0].c_str(), -1, 0);
		sqlite3_bind_text(stmt, 2, secs[i].c_str(), -1, 0);
		sqlite3_bind_int(stmt, 3, vlen - i);
		sqlite3_step(stmt);
		sqlite3_reset(stmt);
	}
}
void ImportLine_duoyi_py(sqlite3_stmt* stmt, std::string& line, char& delimiters, int& paras) {
	std::vector<std::string> secs;
	split(line, secs, delimiters);
	int vlen = (int)secs.size();
	std::string ss = szm(secs[0]).c_str();
	for (int i = 1; i < vlen; i++) {
		sqlite3_bind_text(stmt, 1, secs[0].c_str(), -1, 0);
		sqlite3_bind_text(stmt, 2, secs[i].c_str(), -1, 0);
		sqlite3_bind_int(stmt, 3, vlen - i);
		sqlite3_bind_text(stmt, 4, ss.c_str(), -1, 0);
		sqlite3_step(stmt);
		sqlite3_reset(stmt);
	}
}
void ImportLine_json(sqlite3_stmt* stmt, std::string& line, char& delimiters, int& paras) {
	std::vector<std::string> secs;
	jsonsplit(line, secs);
	if (secs.size() != 3) {
		return;
	}
	sqlite3_bind_text(stmt, 1, secs[0].c_str(), -1, 0);
	sqlite3_bind_text(stmt, 2, secs[1].c_str(), -1, 0);
	sqlite3_bind_text(stmt, 3, secs[2].c_str(), -1, 0);
	sqlite3_step(stmt);
	sqlite3_reset(stmt);
}